#include "htsc_grpc_consumer_trace.h"
#include <string.h>
#include "grpc/support/tls.h"
#include "htsc_grpc_common.h"
#include "htsc_grpc_utils.h"
#include "htsc_grpc_common_utils.h"
#include "htsc_grpc_consumer_trace_sample.h"
#include "grpc/support/thd.h"
//------------------start deal  consumer threadlocal traceinfo------------------
//获取流式推送时，生成及发送服务跟踪信息时间间隔，单位毫秒，默认值5000毫秒即5秒钟。
static uint64_t g_htsc_grpc_push_trace_interval = 5000;

GPR_TLS_DECL(htsc_grpc_consumer_traceinfo);

static void htsc_grpc_enter_ctx(hstc_grpc_common_traceinfo_t *traceinfo) {
	//GPR_ASSERT(gpr_tls_get(&htsc_grpc_consumer_traceinfo) == 0);
	gpr_tls_set(&htsc_grpc_consumer_traceinfo, (intptr_t)traceinfo);
}


//清除threadlocal对象
 void htsc_grpc_threadlocal_clear(hstc_grpc_common_traceinfo_t *traceinfo) {
	 intptr_t pt = gpr_tls_get(&htsc_grpc_consumer_traceinfo);
	//校验threadlocal是否一致
	//GPR_ASSERT(gpr_tls_get(&htsc_grpc_consumer_traceinfo) == (intptr_t)traceinfo);
	 if (pt > 0) {
		 hstc_grpc_common_traceinfo_t *c = (hstc_grpc_common_traceinfo_t *)gpr_tls_get(&htsc_grpc_consumer_traceinfo);
		 //printf("\n-------------threadid: %d ",c->callcount);
	 }

	gpr_tls_set(&htsc_grpc_consumer_traceinfo, 0);
}

 //获取当前存放的threadlocal信息
 hstc_grpc_common_traceinfo_t *htsc_grpc_consumer_getcurrenttrace() {
	 hstc_grpc_common_traceinfo_t *c = (hstc_grpc_common_traceinfo_t *)gpr_tls_get(&htsc_grpc_consumer_traceinfo);
	 return c;
 }
 
//销毁trace对象
void destroy_htsc_grpc_consumer_trace(hstc_grpc_common_traceinfo_t * traceinfo)
{
	htsc_grpc_threadlocal_clear(traceinfo);
}

//组织C端的监控内容
 hstc_grpc_common_traceinfo_t *htsc_grpc_consumer_newfirsttrace(const char *fullmethod)
 { 
	 //获取threadid,把threadid存入threadlocal对象
	 //gpr_thd_id currentid = gpr_thd_currentid();
	 size_t size = 37 * sizeof(char);
	 char *traceid = (char *)malloc(size);
	 memset(traceid, 0, size);
	 htsc_grpc_uuid(traceid);
	 //traceinfo = (hstc_grpc_common_traceinfo_t*)gpr_zalloc(sizeof(hstc_grpc_common_traceinfo_t));
	 hstc_grpc_common_traceinfo_t *traceinfo = (hstc_grpc_common_traceinfo_t*)gpr_zalloc(sizeof(hstc_grpc_common_traceinfo_t));
	 traceinfo->traceid = traceid;
	 traceinfo->parentchainid = "";                        //无需释放
	 traceinfo->chainid = "0";                             //无需释放
	 traceinfo->callcount = 0;
	 //traceinfo->callcount = (int)GetCurrentThreadId();   //暂存thread id
	 traceinfo->initial = true;
	 traceinfo->servicename = htsc_grpc_getserveice_by_fullmethod(fullmethod);
	 traceinfo->methodname = htsc_grpc_getmethodname_by_fullmethod(fullmethod);
	 traceinfo->success = true;
	 traceinfo->consumerside = true;
	 traceinfo->consumerhost = get_local_ip();                     //无需释放
	 traceinfo->consumerport = 0;                                //无需释放
	 traceinfo->protocol = HTSC_GRPC_TRACE_PROTOCOL;             //无需释放
	 traceinfo->appname = htsc_get_provider_AppName();             //无需释放
	 traceinfo->servicegroup = NULL;	                           //无需释放;
	 traceinfo->serviceversion = htsc_grpc_version();              //无需释放;
	 traceinfo->starttime = htsc_get_timestamp_in_mills();
	 //当前设置为不采样时，直接发送kafka
	 if (htsc_grpc_consumer_trace_issample() == HTSC_GRPC_KAFKA_FLAG_UNSAMPLE) {
		 //需发送kafka
		 traceinfo->writekafka = 1;
	 } else { //根据采样算法计算出是否需要发kafka 
		 traceinfo->writekafka = htsc_grpc_consumer_trace_getsampleflag();
	 }
	 traceid = NULL;
	 return traceinfo;
}

 //根据chainid规则生成chainid
 void htsc_grpc_consumer_trace_newchainid(hstc_grpc_common_traceinfo_t *threadtrace,char *chainid) {
	 //chain = "0.-1";
	 if (threadtrace->callcount< 0 || threadtrace->parentchainid == NULL 
		 || strlen(threadtrace->parentchainid)==0) {
		 return;
	 }
	 //传给C
	 int plen = strlen(threadtrace->parentchainid);
	 if (threadtrace->consumerside == false || plen < 3){
		 memcpy(chainid,threadtrace->parentchainid, strlen(threadtrace->parentchainid) * sizeof(char));
		 return;
	 }

	 //待改写代码 
	 int len = plen + 10;
	 char *chain = (char*)malloc(len * sizeof(char));
	 memset(chain, 0, len * sizeof(char));
	 // 当前系统即为服务提供者，也为服务消费者；在调用其他服务提供者的时候，chainId有特殊的计算办法
	 strcpy(chain, threadtrace->parentchainid);
	 int count = threadtrace->callcount; 
	 char *p = strrchr(chain,'.');
	 if ((p- chain)> 1) {
		 memcpy(chainid, chain, (p - chain) * sizeof(char));
		 strcat(chainid, "-1");
	 }
	 p = NULL;
	 FREE_PTR(chain);
	 

	 //String chain = span.getParentChainId();
	 //long count = span.getCallCount();
	 //// 当前系统即为服务提供者，也为服务消费者；在调用其他服务提供者的时候，chainId有特殊的计算办法
	 //if (span.isConsumerSide() && count > 0 && !isEmpty(chain) && chain.length() >= 3) {
		// int pos = chain.lastIndexOf(GlobalConstants.CHAINID_SEPARATOR);
		// if (pos >= 1 && pos + 1 < chain.length()) {
		//	 String prefix = chain.substring(0, pos + 1);// 包含分隔符
		//	 if (!isEmpty(prefix)) {
		//		 chain = prefix + String.valueOf(count);
		//	 }
		// }
	 //}
	 //return chain;
 }

 /*
 * 
 * 根据P传递或C传递给C信息重新组织trace信息
 * fullmethod:方法全名
 * servertrace：P端trace信息
 */
 hstc_grpc_common_traceinfo_t *htsc_grpc_consumer_newmiddletrace(const char *fullmethod,
	 hstc_grpc_common_traceinfo_t *threadtrace) {
	 
	 //校验threadlocal内部，consumerside标记校验threadlocal的来源
	 //来自P端和C端时，有不同的处置流程。

	 hstc_grpc_common_traceinfo_t *traceinfo = (hstc_grpc_common_traceinfo_t*)gpr_zalloc(sizeof(hstc_grpc_common_traceinfo_t));
	
	 if (threadtrace->consumerside == false) {	
		 // 一个系统即作为服务端，又作为客户端的情况
		 // Consumer A --> Provider B(&Consumer B) --> Provider C
		 traceinfo->consumerside = true;   //修改为消费端标记
		 traceinfo->callcount = 0;  // 从0开始计数
	 }
	 //分配空间
	 traceinfo->traceid = threadtrace->traceid;
	 traceinfo->parentchainid = threadtrace->parentchainid;
	 //chainid 生成
	 size_t size = 1000 * sizeof(char);
	 traceinfo->chainid = (char*)malloc(size);
	 memset(traceinfo->chainid, 0, size);
	 htsc_grpc_consumer_trace_newchainid(traceinfo,traceinfo->chainid);

	 traceinfo->callcount = traceinfo->callcount + 1;
	 traceinfo->initial = false;
	 traceinfo->servicename = htsc_grpc_getserveice_by_fullmethod(fullmethod);
	 traceinfo->methodname = htsc_grpc_getmethodname_by_fullmethod(fullmethod);
	 traceinfo->success = true;
	 traceinfo->consumerside = true;
	 traceinfo->consumerhost = get_local_ip();
	 traceinfo->consumerport = 0;
	 traceinfo->protocol = HTSC_GRPC_TRACE_PROTOCOL;
	 traceinfo->appname = htsc_get_provider_AppName();             //无需释放
	 traceinfo->servicegroup = NULL;                               //无需释放
	 traceinfo->serviceversion = htsc_grpc_version();  //无需释放
	 traceinfo->starttime = htsc_get_timestamp_in_mills();
	 traceinfo->writekafka = threadtrace->writekafka;  	

	 return traceinfo; 
 }

 /*
 * 在C端调用方法时，生成trace信息.
 */
 hstc_grpc_common_traceinfo_t *htsc_grpc_consumer_gentrace(const char *fullmethod) {
	 //调用threadlocal实现接口，校验线程变量是否存在
	 //如果线程变量不存在，说明当前是首节点,新建C端trace对象
	 //如果现场变量已存在，说明当前非首节点,说明当前节点及既是P端
	 //获取当前P的trace信息、生成C端trace。

	 //待实现调用threadlocal接口及测试
	 //如果节点为P端的C节点，多次调用P端时，
	 //hstc_grpc_common_traceinfo_t *threadtrace = htsc_grpc_consumer_getcurrenttrace();
	 //if (threadtrace == NULL) {
		// //获取本来providerthreadlocal huyntodo
		// //如果本地作为provider，同时调用下级provider时，可以获取到provider值
	 //}
	 hstc_grpc_trace_threadlocal_t *threadlocal = htsc_grpc_trace_threadlocal_getcurrenttrace();
	 hstc_grpc_common_traceinfo_t *clienttrace = NULL; //(hstc_grpc_common_traceinfo_t*)gpr_zalloc(sizeof(hstc_grpc_common_traceinfo_t));


	 //首先校验C和P threadlocal是否存在
	 //获取C和P的threadlocal如果都不存在
	 if (threadlocal == NULL) {
		 clienttrace = htsc_grpc_consumer_newfirsttrace(fullmethod);

		 //首节不需要持续计数，可以考虑不需要存放threadlocal 待验证
		 threadlocal = (hstc_grpc_trace_threadlocal_t*)gpr_zalloc(sizeof(hstc_grpc_trace_threadlocal_t));	
	 } else { 
		 if(threadlocal->consumertrace ==NULL) {
			 clienttrace = htsc_grpc_consumer_newmiddletrace(fullmethod, threadlocal->consumertrace);
		 } else {
			 clienttrace = htsc_grpc_consumer_newmiddletrace(fullmethod, threadlocal->providertrace);
		 }		
	 }

	 //组织代存入的threadlocal对象，写入threadlocal
	 threadlocal->consumertrace = clienttrace;
	 htsc_grpc_trace_threadlocal_enter(threadlocal);
	 return clienttrace;
 } 


 //consumer 服务调用返回处理
 //serverhost 取值为 ipv4:ip:port 例如：ipv4:10.10.10.10:8888
 void htsc_grpc_consumer_callfinish(hstc_grpc_common_traceinfo_t *traceinfo,bool issuccess,char *serverhost) {
	 //解析serverhost
	 char *p = strchr(serverhost,':')+1;
	 char *pvalue = strchr(p, ':') + 1;
	 if ((pvalue - p) > 1) {
		 size_t size = sizeof(char) * 100;
		 traceinfo->providerhost = (char*)malloc(size);
		 memset(traceinfo->providerhost, 0, size);
		 memcpy(traceinfo->providerhost, p, sizeof(char)*(pvalue - p-1));
	 }

	 pvalue = strrchr(serverhost, ':') + 1;
	 if (pvalue != NULL) {
		 size_t size = sizeof(char) * 100;
		 char* port = (char*)malloc(size);
		 memset(port, 0, size);
		 memcpy(port, pvalue, sizeof(char)*(serverhost+strlen(serverhost) - pvalue));
		 traceinfo->providerport = atoi(port);
		 free(port);
	 }
	 p = NULL;
	 pvalue = NULL;
	 traceinfo->success = issuccess;

	 //把服务跟踪信息写入队列
	 htsc_grpc_trace_write_queue(traceinfo);

	 //清除thread变量
	 //首节点在此处释放、中间节点在调用返回后释放。
	 if (traceinfo->initial == true) {
		 //首节点清除，非首节点在server端清除
		 htsc_grpc_trace_threadlocal_clear();

		 //printf("\n-------------- thread:%d ", GetCurrentThreadId());
		 htsc_grpc_trace_free(&traceinfo);
	 }
 }
 

 /*
 * func：生成流式推送consumer端推动信息
 * auth：huyn
 * date：20170828
 */
 hstc_grpc_common_traceinfo_t *htsc_grpc_consumer_newpushtrace(hstc_grpc_common_traceinfo_t *trace) {
	 hstc_grpc_common_traceinfo_t *traceinfo = (hstc_grpc_common_traceinfo_t*)gpr_zalloc(sizeof(hstc_grpc_common_traceinfo_t));
	 size_t size = 37 * sizeof(char);
	 char *traceid = (char *)malloc(size);
	 memset(traceid, 0, size);
	 htsc_grpc_uuid(traceid);
	 traceinfo->traceid = traceid;
	 traceinfo->parentchainid = "";                              //无需释放
	 traceinfo->chainid = "0";                                   //无需释放
	 traceinfo->callcount = 0;
	 traceinfo->initial = true;
	 traceinfo->servicename = trace->servicename;
	 traceinfo->methodname =  trace->methodname;
	 traceinfo->success = true;
	 traceinfo->consumerside = true;
	 traceinfo->consumerhost = trace->consumerhost;                //无需释放
	 traceinfo->consumerport = 0;                                //无需释放
	 traceinfo->protocol = HTSC_GRPC_TRACE_PROTOCOL;             //无需释放
	 traceinfo->appname = htsc_get_provider_AppName();             //无需释放
	 traceinfo->servicegroup = NULL;	                           //无需释放;
	 traceinfo->serviceversion = htsc_grpc_version();  //无需释放;
	 traceinfo->starttime = htsc_get_timestamp_in_mills();
	 traceinfo->writekafka = 1;
	 traceinfo->pushtime = 0;
	 traceid = NULL;
	 return traceinfo;
 }

 //获取流式推送时，生成及发送服务跟踪信息时间间隔
 uint64_t htsc_grpc_push_trace_interval_get() {
	 return g_htsc_grpc_push_trace_interval;
 }